#include "interval.h"
#include <stdlib.h>

/* 初始化时长测量，在堆中分配一个链表节点，并使调用函数的指针指向该节点
 * @param node：链表头节点指针，函数中可能需要修改头指针指向位置，所以传入双重指针
 * @retval：错误类型，内存分配错误返回NODE_MEM_ERROR，无错误返回NODE_OK
 */
node_error_no_t time_interval_init(time_interval_t **node)
{
    time_interval_t *node_ptr = (time_interval_t *)malloc(sizeof(time_interval_t));
    if (node_ptr == NULL)
    {
        return NODE_MEM_ERROR;
    }
    node_ptr->node_id = NODE_ID_DEFAULT;
    node_ptr->next = NULL;
    node_ptr->previous = NULL;
    *node = node_ptr;
    return NODE_OK;
}

/*计时开始，添加计时节点
 * @param node_id：要添加的节点ID
 * @param node：链表头节点指针
 * @retval：错误类型，节点ID错误返回NODE_ID_ERROR，有相同节点返回NODE_ID_ALREADY_EXIST
 * 内存分配错误返回NODE_MEM_ERROR，无错误返回NODE_OK
 */
node_error_no_t time_interval_begin(int32_t node_id, time_interval_t *node)
{
    time_interval_t *node_ptr = node;

    if (node_id < 0)
    {
        return NODE_ID_ERROR;
    }

    /*头节点为空的话*/
    if (node_ptr->node_id == NODE_ID_DEFAULT)
    {
        node_ptr->node_id = node_id;
        node_ptr->hal_ms = HAL_MS_COUNT;
        node_ptr->ticks1 = SYSTICK_COUNT;
        return NODE_OK;
    }

    /*查找是否有相同的计时节点ID
     * 是的话返回错误标志
     * 否则指针指向尾节点
     */
    for (;;)
    {
        if (node_id == node_ptr->node_id)
        {
            return NODE_ID_ALREADY_EXIST;
        }
        else
        {
            if (node_ptr->next != NULL)
            {
                node_ptr = node_ptr->next;
            }
            else
            {
                break;
            }
        }
    }
    /*在堆中为新节点分配内存空间*/
    time_interval_t *node_ptr_new = (time_interval_t *)malloc(sizeof(time_interval_t));
    if (node_ptr_new == NULL)
    {
        return NODE_MEM_ERROR;
    }
    /*链表添加新节点*/
    node_ptr_new->next = NULL;
    node_ptr_new->previous = node_ptr;
    node_ptr->next = node_ptr_new;

    /*读取时间参数*/
    node_ptr_new->node_id = node_id;
    node_ptr_new->hal_ms = HAL_MS_COUNT;
    node_ptr_new->ticks1 = SYSTICK_COUNT;
    return NODE_OK;
}

/*计时结束
 * @param node_id：计时结束的节点ID
 * @param node：链表头节点指针
 * @retval：错误类型，节点名错误返回NODE_ID_ERROR，
 * 没找到相同节点返回NODE_ID_NOT_EXIST，无错误返回NODE_OK
 */
node_error_no_t time_interval_end(int32_t node_id, time_interval_t *node)
{
    /*读取时间参数*/
    uint32_t ticks_temp = SYSTICK_COUNT;
    uint32_t hal_ms_temp = HAL_MS_COUNT;
    time_interval_t *node_ptr = node;

    if (node_id < 0)
    {
        return NODE_ID_ERROR;
    }

    for (;;)
    {
        /*找到相应的计时节点，并计算计时阶段的节拍数*/
        if (node_id == node_ptr->node_id)
        {
            node_ptr->hal_ms = hal_ms_temp - node_ptr->hal_ms;
            node_ptr->ticks2 = ticks_temp;
            node_ptr->ticks = node_ptr->ticks1 + node_ptr->hal_ms * (SYSTEM_CLOCK_HZ / HAL_TIME_BASE_HZ) - node_ptr->ticks2;
            return NODE_OK;
        }
        else
        {
            if (node_ptr->next != NULL)
            {
                node_ptr = node_ptr->next;
            }
            else
            {
                return NODE_ID_NOT_EXIST;
            }
        }
    }
}

/* 删除当前节点
 * @param node：指向头节点指针的指针
 * @param node_ptr：要删除的节点指针
 * @retval：无错误返回NODE_OK
 */
static node_error_no_t node_del(time_interval_t **node, time_interval_t *node_ptr)
{
    /*要删除的为中间节点*/
    if ((node_ptr->previous != NULL) && (node_ptr->next != NULL))
    {
        node_ptr->previous->next = node_ptr->next;
        node_ptr->next->previous = node_ptr->previous;
        free(node_ptr);
        node_ptr = NULL;
    }
    /*要删除的为头节点，头节点指针后移*/
    else if ((node_ptr->previous == NULL) && (node_ptr->next != NULL))
    {
        node_ptr->next->previous = NULL;
        *node = node_ptr->next;
        free(node_ptr);
        node_ptr = NULL;
    }
    /*要删除的为尾节点*/
    else if ((node_ptr->previous != NULL) && (node_ptr->next == NULL))
    {
        node_ptr->previous->next = NULL;
        free(node_ptr);
        node_ptr = NULL;
    }
    /*要删除的为唯一节点*/
    else
    {
        node_ptr->node_id = NODE_ID_DEFAULT;
    }
    return NODE_OK;
}

/*计算计时节点的时长，计算完成后在链表中删除当前节点
 * @param node_id: 计时节点ID
 * @param node：链表头节点指针，函数中可能需要修改头指针指向位置，所以传入双重指针
 * @param time_interval：保存时长计算结果，0则代表给定时长单位不支持
 * @param uint：时长结果的单位，纳秒、微秒或毫秒，在头文件中定义有相应的枚举类型
 * @retval：错误类型，无错误返回NODE_OK
 */
node_error_no_t time_interval_cal(int32_t node_id, time_interval_t **node, uint32_t *time_interval, enum time_interval_unit unit)
{
    time_interval_t *node_ptr = *node;

    if (node_id < 0)
    {
        return NODE_ID_ERROR;
    }

    for (;;)
    {
        /*找到相应的计时节点，并计算计时阶段的时长*/
        if (node_id == node_ptr->node_id)
        {
            switch (unit)
            {
            case (TIME_US):
                *time_interval = node_ptr->ticks / (SYSTEM_CLOCK_HZ / TIME_INTERVAL_CAL_TO_US);
                break;

            case (TIME_MS):
                *time_interval = node_ptr->ticks / (SYSTEM_CLOCK_HZ / TIME_INTERVAL_CAL_TO_MS);
                break;

            default:
                *time_interval = 0;
                break;
            }
            return node_del(node, node_ptr);
        }
        else
        {
            if (node_ptr->next != NULL)
            {
                node_ptr = node_ptr->next;
            }
            else
            {
                return NODE_ID_NOT_EXIST;
            }
        }
    }
}
